home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume4 / uemacs / part3 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  59.3 KB

  1. From: genrad!decvax!minow (Martin Minow)
  2. Subject: MicroEmacs (Part 3 of 6)
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 4, Issue 70
  7. Submitted by: decvax!minow (Martin Minow)
  8.  
  9. #! /bin/sh
  10. # This is a shell archive, meaning:
  11. # 1. Remove everything above the #! /bin/sh line.
  12. # 2. Save the resulting text in a file.
  13. # 3. Execute the file with /bin/sh (not csh) to create the files:
  14. #    random.c
  15. #    region.c
  16. #    search.c
  17. #    symbol.c
  18. #    version.c
  19. #    window.c
  20. #    word.c
  21. # This archive created: Sun Apr 13 11:16:33 1986
  22. export PATH; PATH=/bin:$PATH
  23. echo shar: extracting "'random.c'" '(10957 characters)'
  24. if test -f 'random.c'
  25. then
  26.     echo shar: will not over-write existing file "'random.c'"
  27. else
  28. cat << \SHAR_EOF > 'random.c'
  29. /*
  30.  * Name:    MicroEMACS
  31.  *        Assorted commands.
  32.  * Version:    29
  33.  * Last edit:    10-Feb-86
  34.  * By:        rex::conroy
  35.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  36.  *
  37.  * The file contains the command
  38.  * processors for a large assortment of unrelated
  39.  * commands. The only thing they have in common is
  40.  * that they are all command processors.
  41.  */
  42. #include    "def.h"
  43.  
  44. /*
  45.  * Display a bunch of useful information about
  46.  * the current location of dot. The character under the
  47.  * cursor (in octal), the current line, row, and column, and
  48.  * approximate position of the cursor in the file (as a percentage)
  49.  * is displayed. The column position assumes an infinite position
  50.  * display; it does not truncate just because the screen does.
  51.  * This is normally bound to "C-X =".
  52.  */
  53. showcpos(f, n, k)
  54. {
  55.     register LINE    *clp;
  56.     register int    cbo;
  57.     register int    nchar;
  58.     register int    cchar;
  59.     register int    nline;
  60.     register int    cline;
  61.     register int    cbyte;
  62.     register int    ratio;
  63.     register int    row;
  64.     register int    col;
  65.     register int    i;
  66.     register int    c;
  67.  
  68.     clp = lforw(curbp->b_linep);        /* Collect the data.    */
  69.     cbo = 0;
  70.     nchar = 0;
  71.     nline = 1;                /* Origin 1.        */
  72.     for (;;) {
  73.         if (clp == curwp->w_dotp) {
  74.             cline = nline;
  75.             if (cbo == curwp->w_doto) {
  76.                 cchar = nchar;
  77.                 if (cbo == llength(clp))
  78.                     cbyte = '\n';
  79.                 else
  80.                     cbyte = lgetc(clp, cbo);
  81.             }
  82.         }
  83.         if (cbo == llength(clp)) {
  84.             if (clp == curbp->b_linep)
  85.                 break;
  86.             clp = lforw(clp);
  87.             cbo = 0;
  88.             ++nline;        /* Count a line.    */
  89.         } else
  90.             ++cbo;
  91.         ++nchar;            /* Count a character.    */
  92.     }
  93.     row = curwp->w_toprow;            /* Determine row.    */
  94.     clp = curwp->w_linep;
  95.     while (clp!=curbp->b_linep && clp!=curwp->w_dotp) {
  96.         ++row;
  97.         clp = lforw(clp);
  98.     }
  99.     ++row;                    /* Convert to origin 1.    */
  100.     col = 0;                /* Determine column.    */
  101.     for (i=0; i<curwp->w_doto; ++i) {
  102.         c = lgetc(curwp->w_dotp, i);
  103.         if (c == '\t')
  104.             col |= 0x07;
  105.         else if (ISCTRL(c) != FALSE)
  106.             ++col;
  107.         ++col;
  108.     }
  109.     ++col;                    /* Convert to origin 1.    */
  110.     ratio = 0;                /* Ratio before dot.    */
  111.     if (nchar != 0) {
  112.         ratio = (100L*cchar) / nchar;
  113.         if (ratio==0 && cchar!=0)    /* Allow 0% only at the    */
  114.             ratio = 1;        /* start of the file.    */
  115.     }
  116.     eprintf("[CH:0%o Line:%d Row:%d Col:%d %d%% of %d]",
  117.         cbyte, cline, row, col, ratio, nchar);
  118.     return (TRUE);
  119. }
  120.  
  121. /*
  122.  * Twiddle the two characters on either side of
  123.  * dot. If dot is at the end of the line twiddle the
  124.  * two characters before it. Return with an error if dot
  125.  * is at the beginning of line; it seems to be a bit
  126.  * pointless to make this work. This fixes up a very
  127.  * common typo with a single stroke. Normally bound
  128.  * to "C-T". This always works within a line, so
  129.  * "WFEDIT" is good enough.
  130.  */
  131. twiddle(f, n, k)
  132. {
  133.     register LINE    *dotp;
  134.     register int    doto;
  135.     register int    cl;
  136.     register int    cr;
  137.  
  138.     dotp = curwp->w_dotp;
  139.     doto = curwp->w_doto;
  140.     if (doto==llength(dotp) && --doto<0)
  141.         return (FALSE);
  142.     cr = lgetc(dotp, doto);
  143.     if (--doto < 0)
  144.         return (FALSE);
  145.     cl = lgetc(dotp, doto);
  146.     lputc(dotp, doto+0, cr);
  147.     lputc(dotp, doto+1, cl);
  148.     lchange(WFEDIT);
  149.     return (TRUE);
  150. }
  151.  
  152. /*
  153.  * Quote the next character, and
  154.  * insert it into the buffer. All the characters
  155.  * are taken literally, with the exception of the newline,
  156.  * which always has its line splitting meaning. The character
  157.  * is always read, even if it is inserted 0 times, for
  158.  * regularity.
  159.  */
  160. quote(f, n, k)
  161. {
  162.     register int    s;
  163.     register int    c;
  164.  
  165.     if (kbdmop != NULL)
  166.         c = *kbdmop++;
  167.     else {
  168.         c = ttgetc();
  169.         if (kbdmip != NULL) {
  170.             if (kbdmip > &kbdm[NKBDM-4]) {
  171.                 ctrlg(FALSE, 0, KRANDOM);
  172.                 return (ABORT);
  173.             }
  174.             *kbdmip++ = c;
  175.         }
  176.     }
  177.     if (n < 0)
  178.         return (FALSE);
  179.     if (n == 0)
  180.         return (TRUE);
  181.     if (c == '\n') {
  182.         do {
  183.             s = lnewline();
  184.         } while (s==TRUE && --n);
  185.         return (s);
  186.     }
  187.     return (linsert(n, c));
  188. }
  189.  
  190. /*
  191.  * Ordinary text characters are bound to this function,
  192.  * which inserts them into the buffer. Characters marked as control
  193.  * characters (using the CTRL flag) may be remapped to their ASCII
  194.  * equivalent. This makes TAB (C-I) work right, and also makes the
  195.  * world look reasonable if a control character is bound to this
  196.  * this routine by hand. Any META or CTLX flags on the character
  197.  * are discarded. This is the only routine that actually looks
  198.  * the the "k" argument.
  199.  */
  200. selfinsert(f, n, k)
  201. {
  202.     register int    c;
  203.  
  204.     if (n < 0)
  205.         return (FALSE);
  206.     if (n == 0)
  207.         return (TRUE);
  208.     c = k & KCHAR;
  209.     if ((k&KCTRL)!=0 && c>='@' && c<='_')    /* ASCII-ify.        */
  210.         c -= '@';
  211.     return (linsert(n, c));
  212. }
  213.  
  214. /*
  215.  * Open up some blank space. The basic plan
  216.  * is to insert a bunch of newlines, and then back
  217.  * up over them. Everything is done by the subcommand
  218.  * procerssors. They even handle the looping. Normally
  219.  * this is bound to "C-O".
  220.  */
  221. openline(f, n, k)
  222. {
  223.     register int    i;
  224.     register int    s;
  225.  
  226.     if (n < 0)
  227.         return (FALSE);
  228.     if (n == 0)
  229.         return (TRUE);
  230.     i = n;                    /* Insert newlines.    */
  231.     do {
  232.         s = lnewline();
  233.     } while (s==TRUE && --i);
  234.     if (s == TRUE)                /* Then back up overtop    */
  235.         s = backchar(f, n, KRANDOM);    /* of them all.        */
  236.     return (s);
  237. }
  238.  
  239. /*
  240.  * Insert a newline.
  241.  * If you are at the end of the line and the
  242.  * next line is a blank line, just move into the
  243.  * blank line. This makes "C-O" and "C-X C-O" work
  244.  * nicely, and reduces the ammount of screen
  245.  * update that has to be done. This would not be
  246.  * as critical if screen update were a lot
  247.  * more efficient.
  248.  */
  249. newline(f, n, k)
  250. {
  251.     register LINE    *lp;
  252.     register int    s;
  253.  
  254.     if (n < 0)
  255.         return (FALSE);
  256.     while (n--) {
  257.         lp = curwp->w_dotp;
  258.         if (llength(lp) == curwp->w_doto
  259.         && lp != curbp->b_linep
  260.         && llength(lforw(lp)) == 0) {
  261.             if ((s=forwchar(FALSE, 1, KRANDOM)) != TRUE)
  262.                 return (s);
  263.         } else if ((s=lnewline()) != TRUE)
  264.             return (s);
  265.     }
  266.     return (TRUE);
  267. }
  268.  
  269. /*
  270.  * Delete blank lines around dot.
  271.  * What this command does depends if dot is
  272.  * sitting on a blank line. If dot is sitting on a
  273.  * blank line, this command deletes all the blank lines
  274.  * above and below the current line. If it is sitting
  275.  * on a non blank line then it deletes all of the
  276.  * blank lines after the line. Normally this command
  277.  * is bound to "C-X C-O". Any argument is ignored.
  278.  */
  279. deblank(f, n, k)
  280. {
  281.     register LINE    *lp1;
  282.     register LINE    *lp2;
  283.     register int    nld;
  284.  
  285.     lp1 = curwp->w_dotp;
  286.     while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
  287.         lp1 = lp2;
  288.     lp2 = lp1;
  289.     nld = 0;
  290.     while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
  291.         ++nld;
  292.     if (nld == 0)
  293.         return (TRUE);
  294.     curwp->w_dotp = lforw(lp1);
  295.     curwp->w_doto = 0;
  296.     return (ldelete(nld, FALSE));
  297. }
  298.  
  299. /*
  300.  * Insert a newline, then enough
  301.  * tabs and spaces to duplicate the indentation
  302.  * of the previous line. Assumes tabs are every eight
  303.  * characters. Quite simple. Figure out the indentation
  304.  * of the current line. Insert a newline by calling
  305.  * the standard routine. Insert the indentation by
  306.  * inserting the right number of tabs and spaces.
  307.  * Return TRUE if all ok. Return FALSE if one
  308.  * of the subcomands failed. Normally bound
  309.  * to "C-J".
  310.  */
  311. indent(f, n, k)
  312. {
  313.     register int    nicol;
  314.     register int    c;
  315.     register int    i;
  316.  
  317.     if (n < 0)
  318.         return (FALSE);
  319.     while (n--) {
  320.         nicol = 0;
  321.         for (i=0; i<llength(curwp->w_dotp); ++i) {
  322.             c = lgetc(curwp->w_dotp, i);
  323.             if (c!=' ' && c!='\t')
  324.                 break;
  325.             if (c == '\t')
  326.                 nicol |= 0x07;
  327.             ++nicol;
  328.         }
  329.         if (lnewline() == FALSE
  330.         || ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE)
  331.         || ((i=nicol%8)!=0 && linsert(i,  ' ')==FALSE))
  332.             return (FALSE);
  333.     }
  334.     return (TRUE);
  335. }
  336.  
  337. /*
  338.  * Delete forward. This is real
  339.  * easy, because the basic delete routine does
  340.  * all of the work. Watches for negative arguments,
  341.  * and does the right thing. If any argument is
  342.  * present, it kills rather than deletes, to prevent
  343.  * loss of text if typed with a big argument.
  344.  * Normally bound to "C-D".
  345.  */
  346. forwdel(f, n, k)
  347. {
  348.     if (n < 0)
  349.         return (backdel(f, -n, KRANDOM));
  350.     if (f != FALSE) {            /* Really a kill.    */
  351.         if ((lastflag&CFKILL) == 0)
  352.             kdelete();
  353.         thisflag |= CFKILL;
  354.     }
  355.     return (ldelete(n, f));
  356. }
  357.  
  358. /*
  359.  * Delete backwards. This is quite easy too,
  360.  * because it's all done with other functions. Just
  361.  * move the cursor back, and delete forwards.
  362.  * Like delete forward, this actually does a kill
  363.  * if presented with an argument.
  364.  */
  365. backdel(f, n, k)
  366. {
  367.     register int    s;
  368.  
  369.     if (n < 0)
  370.         return (forwdel(f, -n, KRANDOM));
  371.     if (f != FALSE) {            /* Really a kill.    */
  372.         if ((lastflag&CFKILL) == 0)
  373.             kdelete();
  374.         thisflag |= CFKILL;
  375.     }
  376.     if ((s=backchar(f, n, KRANDOM)) == TRUE)
  377.         s = ldelete(n, f);
  378.     return (s);
  379. }
  380.  
  381. /*
  382.  * Kill line. If called without an argument,
  383.  * it kills from dot to the end of the line, unless it
  384.  * is at the end of the line, when it kills the newline.
  385.  * If called with an argument of 0, it kills from the
  386.  * start of the line to dot. If called with a positive
  387.  * argument, it kills from dot forward over that number
  388.  * of newlines. If called with a negative argument it
  389.  * kills any text before dot on the current line,
  390.  * then it kills back abs(arg) lines.
  391.  */
  392. killline(f, n, k)
  393. {
  394.     register int    chunk;
  395.     register LINE    *nextp;
  396.  
  397.     if ((lastflag&CFKILL) == 0)        /* Clear kill buffer if    */
  398.         kdelete();            /* last wasn't a kill.    */
  399.     thisflag |= CFKILL;
  400.     if (f == FALSE) {
  401.         chunk = llength(curwp->w_dotp)-curwp->w_doto;
  402.         if (chunk == 0)
  403.             chunk = 1;
  404.     } else if (n > 0) {
  405.         chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
  406.         nextp = lforw(curwp->w_dotp);
  407.         while (--n) {
  408.             if (nextp == curbp->b_linep)
  409.                 return (FALSE);
  410.             chunk += llength(nextp)+1;
  411.             nextp = lforw(nextp);
  412.         }
  413.     } else {                /* n <= 0        */
  414.         chunk = curwp->w_doto;
  415.         curwp->w_doto = 0;
  416.         while (n++) {
  417.             if (lback(curwp->w_dotp) == curbp->b_linep)
  418.                 break;
  419.             curwp->w_dotp = lback(curwp->w_dotp);
  420.             curwp->w_flag |= WFMOVE;
  421.             chunk += llength(curwp->w_dotp)+1;
  422.         }
  423.     }
  424.     return (ldelete(chunk, TRUE));
  425. }
  426.  
  427. /*
  428.  * Yank text back from the kill buffer. This
  429.  * is really easy. All of the work is done by the
  430.  * standard insert routines. All you do is run the loop,
  431.  * and check for errors. The blank
  432.  * lines are inserted with a call to "newline"
  433.  * instead of a call to "lnewline" so that the magic
  434.  * stuff that happens when you type a carriage
  435.  * return also happens when a carriage return is
  436.  * yanked back from the kill buffer.
  437.  * An attempt has been made to fix the cosmetic bug
  438.  * associated with a yank when dot is on the top line of
  439.  * the window (nothing moves, because all of the new
  440.  * text landed off screen).
  441.  */
  442. yank(f, n, k)
  443. {
  444.     register int    c;
  445.     register int    i;
  446.     register LINE    *lp;
  447.     register int    nline;
  448.  
  449.     if (n < 0)
  450.         return (FALSE);
  451.     nline = 0;                /* Newline counting.    */
  452.     while (n--) {
  453.         i = 0;
  454.         while ((c=kremove(i)) >= 0) {
  455.             if (c == '\n') {
  456.                 if (newline(FALSE, 1, KRANDOM) == FALSE)
  457.                     return (FALSE);
  458.                 ++nline;
  459.             } else {
  460.                 if (linsert(1, c) == FALSE)
  461.                     return (FALSE);
  462.             }
  463.             ++i;
  464.         }
  465.     }
  466.     lp = curwp->w_linep;            /* Cosmetic adjustment    */
  467.     if (curwp->w_dotp == lp) {        /* if offscreen insert.    */
  468.         while (nline-- && lback(lp)!=curbp->b_linep)
  469.             lp = lback(lp);
  470.         curwp->w_linep = lp;        /* Adjust framing.    */
  471.         curwp->w_flag |= WFHARD;
  472.     }
  473.     return (TRUE);
  474. }
  475. SHAR_EOF
  476. if test 10957 -ne "`wc -c < 'random.c'`"
  477. then
  478.     echo shar: error transmitting "'random.c'" '(should have been 10957 characters)'
  479. fi
  480. fi
  481. echo shar: extracting "'region.c'" '(5340 characters)'
  482. if test -f 'region.c'
  483. then
  484.     echo shar: will not over-write existing file "'region.c'"
  485. else
  486. cat << \SHAR_EOF > 'region.c'
  487. /*
  488.  * Name:    MicroEMACS
  489.  *        Region based commands.
  490.  * Version:    29
  491.  * Last edit:    12-Feb-86
  492.  * By:        rex::conroy
  493.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  494.  * What:    Region operations.
  495.  *
  496.  * The routines in this file
  497.  * deal with the region, that magic space
  498.  * between "." and mark. Some functions are
  499.  * commands. Some functions are just for
  500.  * internal use.
  501.  */
  502. #include    "def.h"
  503.  
  504. /*
  505.  * Kill the region. Ask "getregion"
  506.  * to figure out the bounds of the region.
  507.  * Move "." to the start, and kill the characters.
  508.  */
  509. killregion(f, n, k)
  510. {
  511.     register int    s;
  512.     REGION        region;
  513.  
  514.     if ((s=getregion(®ion)) != TRUE)
  515.         return (s);
  516.     if ((lastflag&CFKILL) == 0)        /* This is a kill type    */
  517.         kdelete();            /* command, so do magic    */
  518.     thisflag |= CFKILL;            /* kill buffer stuff.    */
  519.     curwp->w_dotp = region.r_linep;
  520.     curwp->w_doto = region.r_offset;
  521.     return (ldelete(region.r_size, TRUE));
  522. }
  523.  
  524. /*
  525.  * Copy all of the characters in the
  526.  * region to the kill buffer. Don't move dot
  527.  * at all. This is a bit like a kill region followed
  528.  * by a yank.
  529.  */
  530. copyregion(f, n, k)
  531. {
  532.     register LINE    *linep;
  533.     register int    loffs;
  534.     register int    s;
  535.     REGION        region;
  536.  
  537.     if ((s=getregion(®ion)) != TRUE)
  538.         return (s);
  539.     if ((lastflag&CFKILL) == 0)        /* Kill type command.    */
  540.         kdelete();
  541.     thisflag |= CFKILL;
  542.     linep = region.r_linep;            /* Current line.    */
  543.     loffs = region.r_offset;        /* Current offset.    */
  544.     while (region.r_size--) {
  545.         if (loffs == llength(linep)) {    /* End of line.        */
  546.             if ((s=kinsert('\n')) != TRUE)
  547.                 return (s);
  548.             linep = lforw(linep);
  549.             loffs = 0;
  550.         } else {            /* Middle of line.    */
  551.             if ((s=kinsert(lgetc(linep, loffs))) != TRUE)
  552.                 return (s);
  553.             ++loffs;
  554.         }
  555.     }
  556.     return (TRUE);
  557. }
  558.  
  559. /*
  560.  * Lower case region. Zap all of the upper
  561.  * case characters in the region to lower case. Use
  562.  * the region code to set the limits. Scan the buffer,
  563.  * doing the changes. Call "lchange" to ensure that
  564.  * redisplay is done in all buffers. 
  565.  */
  566. lowerregion(f, n, k)
  567. {
  568.     register LINE    *linep;
  569.     register int    loffs;
  570.     register int    c;
  571.     register int    s;
  572.     REGION        region;
  573.  
  574.     if ((s=getregion(®ion)) != TRUE)
  575.         return (s);
  576.     lchange(WFHARD);
  577.     linep = region.r_linep;
  578.     loffs = region.r_offset;
  579.     while (region.r_size--) {
  580.         if (loffs == llength(linep)) {
  581.             linep = lforw(linep);
  582.             loffs = 0;
  583.         } else {
  584.             c = lgetc(linep, loffs);
  585.             if (ISUPPER(c) != FALSE)
  586.                 lputc(linep, loffs, TOLOWER(c));
  587.             ++loffs;
  588.         }
  589.     }
  590.     return (TRUE);
  591. }
  592.  
  593. /*
  594.  * Upper case region. Zap all of the lower
  595.  * case characters in the region to upper case. Use
  596.  * the region code to set the limits. Scan the buffer,
  597.  * doing the changes. Call "lchange" to ensure that
  598.  * redisplay is done in all buffers. 
  599.  */
  600. upperregion(f, n, k)
  601. {
  602.     register LINE    *linep;
  603.     register int    loffs;
  604.     register int    c;
  605.     register int    s;
  606.     REGION        region;
  607.  
  608.     if ((s=getregion(®ion)) != TRUE)
  609.         return (s);
  610.     lchange(WFHARD);
  611.     linep = region.r_linep;
  612.     loffs = region.r_offset;
  613.     while (region.r_size--) {
  614.         if (loffs == llength(linep)) {
  615.             linep = lforw(linep);
  616.             loffs = 0;
  617.         } else {
  618.             c = lgetc(linep, loffs);
  619.             if (ISLOWER(c) != FALSE)
  620.                 lputc(linep, loffs, TOUPPER(c));
  621.             ++loffs;
  622.         }
  623.     }
  624.     return (TRUE);
  625. }
  626.  
  627. /*
  628.  * This routine figures out the bound of the region
  629.  * in the current window, and stores the results into the fields
  630.  * of the REGION structure. Dot and mark are usually close together,
  631.  * but I don't know the order, so I scan outward from dot, in both
  632.  * directions, looking for mark. The size is kept in a long. At the
  633.  * end, after the size is figured out, it is assigned to the size
  634.  * field of the region structure. If this assignment loses any bits,
  635.  * then we print an error. This is "type independent" overflow
  636.  * checking. All of the callers of this routine should be ready to
  637.  * get an ABORT status, because I might add a "if regions is big,
  638.  * ask before clobberring" flag.
  639.  */
  640. getregion(rp)
  641. register REGION    *rp;
  642. {
  643.     register LINE    *flp;
  644.     register LINE    *blp;
  645.     register long    fsize;            /* Long now.        */
  646.     register long    bsize;
  647.  
  648.     if (curwp->w_markp == NULL) {
  649.         eprintf("No mark in this window");
  650.         return (FALSE);
  651.     }
  652.     if (curwp->w_dotp == curwp->w_markp) {    /* "r_size" always ok.    */
  653.         rp->r_linep = curwp->w_dotp;
  654.         if (curwp->w_doto < curwp->w_marko) {
  655.             rp->r_offset = curwp->w_doto;
  656.             rp->r_size = curwp->w_marko-curwp->w_doto;
  657.         } else {
  658.             rp->r_offset = curwp->w_marko;
  659.             rp->r_size = curwp->w_doto-curwp->w_marko;
  660.         }
  661.         return (TRUE);
  662.     }
  663.     blp = curwp->w_dotp;            /* Get region size.    */
  664.     flp = curwp->w_dotp;
  665.     bsize = curwp->w_doto;
  666.     fsize = llength(flp)-curwp->w_doto+1;
  667.     while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
  668.         if (flp != curbp->b_linep) {
  669.             flp = lforw(flp);
  670.             if (flp == curwp->w_markp) {
  671.                 rp->r_linep = curwp->w_dotp;
  672.                 rp->r_offset = curwp->w_doto;
  673.                 return (setsize(rp, fsize+curwp->w_marko));
  674.             }
  675.             fsize += llength(flp)+1;
  676.         }
  677.         if (lback(blp) != curbp->b_linep) {
  678.             blp = lback(blp);
  679.             bsize += llength(blp)+1;
  680.             if (blp == curwp->w_markp) {
  681.                 rp->r_linep = blp;
  682.                 rp->r_offset = curwp->w_marko;
  683.                 return (setsize(rp, bsize-curwp->w_marko));
  684.             }
  685.         }
  686.     }
  687.     eprintf("Bug: lost mark");        /* Gak!            */
  688.     return (FALSE);
  689. }
  690.  
  691. /*
  692.  * Set size, and check for overflow.
  693.  */
  694. setsize(rp, size)
  695. register REGION    *rp;
  696. register long    size;
  697. {
  698.     rp->r_size = size;
  699.     if (rp->r_size != size) {
  700.         eprintf("Region is too large");
  701.         return (FALSE);
  702.     }
  703.     return (TRUE);
  704. }
  705. SHAR_EOF
  706. if test 5340 -ne "`wc -c < 'region.c'`"
  707. then
  708.     echo shar: error transmitting "'region.c'" '(should have been 5340 characters)'
  709. fi
  710. fi
  711. echo shar: extracting "'search.c'" '(14284 characters)'
  712. if test -f 'search.c'
  713. then
  714.     echo shar: will not over-write existing file "'search.c'"
  715. else
  716. cat << \SHAR_EOF > 'search.c'
  717. /*
  718.  * Name:    MicroEMACS
  719.  *         Search commands.
  720.  * Version:    30
  721.  * Last edit:    14-Feb-86
  722.  * By:        rex::conroy, rex::ellison
  723.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  724.  *                           ...!dec-vox!ellison
  725.  *
  726.  * The functions in this file implement the
  727.  * search commands (both plain and incremental searches
  728.  * are supported) and the query-replace command.
  729.  *
  730.  * The plain old search code is part of the original
  731.  * MicroEMACS "distribution". The incremental search code,
  732.  * and the query-replace code, is by Rich Ellison.
  733.  */
  734. #include    "def.h"
  735.  
  736. #define CCHR(x)        ((x)-'@')
  737.  
  738. #define SRCH_BEGIN    (0)            /* Search sub-codes.    */
  739. #define    SRCH_FORW    (-1)
  740. #define SRCH_BACK    (-2)
  741. #define SRCH_PREV    (-3)
  742. #define SRCH_NEXT    (-4)
  743. #define SRCH_NOPR    (-5)
  744. #define SRCH_ACCM    (-6)
  745.  
  746. typedef struct  {
  747.     int    s_code;
  748.     LINE    *s_dotp;
  749.     int    s_doto;
  750. }    SRCHCOM;
  751.  
  752. static    SRCHCOM    cmds[NSRCH];
  753. static    int    cip;
  754.  
  755. int    srch_lastdir = SRCH_NOPR;        /* Last search flags.    */
  756.  
  757. /*
  758.  * Search forward.
  759.  * Get a search string from the user, and search for it,
  760.  * starting at ".". If found, "." gets moved to just after the
  761.  * matched characters, and display does all the hard stuff.
  762.  * If not found, it just prints a message.
  763.  */
  764. forwsearch(f, n, k)
  765. {
  766.     register int    s;
  767.  
  768.     if ((s=readpattern("Search")) != TRUE)
  769.         return (s);
  770.     if (forwsrch() == FALSE) {
  771.         eprintf("Not found");
  772.         return (FALSE);
  773.     }
  774.     srch_lastdir = SRCH_FORW;
  775.     return (TRUE);
  776. }
  777.  
  778. /*
  779.  * Reverse search.
  780.  * Get a search string from the  user, and search, starting at "."
  781.  * and proceeding toward the front of the buffer. If found "." is left
  782.  * pointing at the first character of the pattern [the last character that
  783.  * was matched].
  784.  */
  785. backsearch(f, n, k)
  786. {
  787.     register int    s;
  788.  
  789.     if ((s=readpattern("Reverse search")) != TRUE)
  790.         return (s);
  791.     if (backsrch() == FALSE) {
  792.         eprintf("Not found");
  793.         return (FALSE);
  794.     }
  795.     srch_lastdir = SRCH_BACK;
  796.     return (TRUE);
  797. }
  798.  
  799. /* 
  800.  * Search again, using the same search string
  801.  * and direction as the last search command. The direction
  802.  * has been saved in "srch_lastdir", so you know which way
  803.  * to go.
  804.  */
  805. searchagain(f, n, k)
  806. {
  807.     if (srch_lastdir == SRCH_FORW) {
  808.         if (forwsrch() == FALSE) {
  809.             eprintf("Not found");
  810.             return (FALSE);
  811.         }
  812.         return (TRUE);
  813.     }
  814.     if (srch_lastdir == SRCH_BACK) {
  815.         if (backsrch() == FALSE) {
  816.             eprintf("Not found");
  817.             return (FALSE);
  818.         }
  819.         return (TRUE);
  820.     }
  821.     eprintf("No last search");
  822.     return (FALSE);
  823. }
  824.  
  825. /*
  826.  * Use incremental searching, initially in the forward direction.
  827.  * isearch ignores any explicit arguments.
  828.  */
  829. forwisearch(f, n, k)
  830. {
  831.     return (isearch(SRCH_FORW));
  832. }
  833.  
  834. /*
  835.  * Use incremental searching, initially in the reverse direction.
  836.  * isearch ignores any explicit arguments.
  837.  */
  838. backisearch(f, n, k)
  839. {
  840.     return (isearch(SRCH_BACK));
  841. }
  842.  
  843. /*
  844.  * Incremental Search.
  845.  *    dir is used as the initial direction to search.
  846.  *    ^N    find next occurance  (if first thing typed reuse old string).
  847.  *    ^P    find prev occurance  (if first thing typed reuse old string).
  848.  *    ^S    switch direction to forward, find next
  849.  *    ^R    switch direction to reverse, find prev
  850.  *    ^Q    quote next character (allows searching for ^N etc.)
  851.  *    <ESC>    exit from Isearch.
  852.  *    <DEL>    undoes last character typed. (tricky job to do this correctly).
  853.  *    else    accumulate into search string
  854.  */
  855. isearch(dir)
  856. {
  857.     register int    c;
  858.     register LINE    *clp;
  859.     register int    cbo;
  860.     register int    success;
  861.     int        pptr;
  862.  
  863.     for (cip=0; cip<NSRCH; cip++)
  864.         cmds[cip].s_code = SRCH_NOPR;
  865.     cip = 0;
  866.     pptr = -1;
  867.     clp = curwp->w_dotp;
  868.     cbo = curwp->w_doto;
  869.     is_lpush();
  870.     is_cpush(SRCH_BEGIN);
  871.     success = TRUE;
  872.     is_prompt(dir, TRUE, success);
  873.     for (;;) {
  874.         update();
  875.         switch (c = ttgetc()) {
  876.         case CCHR('M'):
  877.         case METACH:
  878.             srch_lastdir = dir;
  879.             eprintf("[Done]");
  880.             return (TRUE);
  881.  
  882.         case CCHR('G'):
  883.             curwp->w_dotp = clp;
  884.             curwp->w_doto = cbo;
  885.             curwp->w_flag |= WFMOVE;
  886.             srch_lastdir = dir;
  887.             ctrlg(FALSE, 0, KRANDOM);
  888.             return (FALSE);
  889.  
  890.         case CCHR('S'):
  891.         case CCHR('F'):
  892.             if (dir == SRCH_BACK) {
  893.                 dir = SRCH_FORW;
  894.                 is_lpush();
  895.                 is_cpush(SRCH_FORW);
  896.                 success = TRUE;
  897.             }
  898.             /* Drop through to find next. */
  899.         case CCHR('N'):
  900.             if (success==FALSE && dir==SRCH_FORW)
  901.                 break;
  902.             is_lpush();
  903.             forwchar(FALSE, 1, KRANDOM);
  904.             if (is_find(SRCH_NEXT) != FALSE) {
  905.                 is_cpush(SRCH_NEXT);
  906.                 pptr = strlen(pat);
  907.             } else {
  908.                 backchar(FALSE, 1, KRANDOM);
  909.                 ttbeep();
  910.                 success = FALSE;
  911.             }
  912.             is_prompt(dir, FALSE, success);
  913.             break;
  914.  
  915.         case CCHR('R'):
  916.         case CCHR('B'):
  917.             if (dir == SRCH_FORW) {
  918.                 dir = SRCH_BACK;
  919.                 is_lpush();
  920.                 is_cpush(SRCH_BACK);
  921.                 success = TRUE;
  922.             }
  923.             /* Drop through to find previous. */
  924.         case CCHR('P'):
  925.             if (success==FALSE && dir==SRCH_BACK)
  926.                 break;
  927.             is_lpush();
  928.             backchar(FALSE, 1, KRANDOM);
  929.             if (is_find(SRCH_PREV) != FALSE) {
  930.                 is_cpush(SRCH_PREV);
  931.                 pptr = strlen(pat);
  932.             } else {
  933.                 forwchar(FALSE, 1, KRANDOM);
  934.                 ttbeep();
  935.                 success = FALSE;
  936.             }
  937.             is_prompt(dir,FALSE,success);
  938.             break;
  939.  
  940.         case 0x7F:
  941.             if (is_undo(&pptr, &dir) != TRUE)
  942.                 return (ABORT);
  943.             if (is_peek() != SRCH_ACCM)
  944.                 success = TRUE;
  945.             is_prompt(dir, FALSE, success);
  946.             break;
  947.  
  948.         case CCHR('^'):
  949.         case CCHR('Q'):
  950.             c = ttgetc();
  951.         case CCHR('U'):
  952.         case CCHR('X'):
  953.         case CCHR('J'):
  954.             goto  addchar;
  955.  
  956.         default:
  957.             if (ISCTRL(c) != FALSE) {
  958.                 c += '@';
  959.                 c |= KCTRL;
  960.                 success = execute(c, FALSE, 1);
  961.                 curwp->w_flag |= WFMOVE;
  962.                 return (success);
  963.             }                
  964.         addchar:
  965.             if (pptr == -1)
  966.                 pptr = 0;
  967.             if (pptr == 0)
  968.                 success = TRUE;
  969.             pat[pptr++] = c;
  970.             if (pptr == NPAT) {
  971.                 eprintf("Pattern too long");
  972.                 ctrlg(FALSE, 0, KRANDOM);
  973.                 return (ABORT);
  974.             }
  975.             pat[pptr] = '\0';
  976.             is_lpush();
  977.             if (success != FALSE) {
  978.                 if (is_find(dir) != FALSE)
  979.                     is_cpush(c);
  980.                 else {
  981.                     success = FALSE;
  982.                     ttbeep();
  983.                     is_cpush(SRCH_ACCM);
  984.                 }
  985.             } else
  986.                 is_cpush(SRCH_ACCM);
  987.             is_prompt(dir, FALSE, success);
  988.         }
  989.     }
  990. }
  991.  
  992. is_cpush(cmd)
  993. register int    cmd;
  994. {
  995.     if (++cip >= NSRCH)
  996.         cip = 0;
  997.     cmds[cip].s_code = cmd;
  998. }
  999.  
  1000. is_lpush()
  1001. {
  1002.     register int    ctp;
  1003.  
  1004.     ctp = cip+1;
  1005.     if (ctp >= NSRCH)
  1006.         ctp = 0;
  1007.     cmds[ctp].s_code = SRCH_NOPR;
  1008.     cmds[ctp].s_doto = curwp->w_doto;
  1009.     cmds[ctp].s_dotp = curwp->w_dotp;
  1010. }
  1011.  
  1012. is_pop()
  1013. {
  1014.     if (cmds[cip].s_code != SRCH_NOPR) {
  1015.         curwp->w_doto  = cmds[cip].s_doto; 
  1016.         curwp->w_dotp  = cmds[cip].s_dotp;
  1017.         curwp->w_flag |= WFMOVE;
  1018.         cmds[cip].s_code = SRCH_NOPR;
  1019.     }
  1020.     if (--cip <= 0)
  1021.         cip = NSRCH-1;
  1022. }
  1023.  
  1024. is_peek()    
  1025. {
  1026.     if (cip == 0)
  1027.         return (cmds[NSRCH-1].s_code);
  1028.     else
  1029.         return (cmds[cip-1].s_code);
  1030. }
  1031.  
  1032. is_undo(pptr, dir)
  1033. register int    *pptr;
  1034. register int    *dir;
  1035. {
  1036.     switch (cmds[cip].s_code) {
  1037.     case SRCH_NOPR:
  1038.     case SRCH_BEGIN:
  1039.     case SRCH_NEXT:
  1040.     case SRCH_PREV:
  1041.         break;
  1042.  
  1043.     case SRCH_FORW:
  1044.         *dir = SRCH_BACK;
  1045.         break;
  1046.  
  1047.     case SRCH_BACK:
  1048.         *dir = SRCH_FORW;
  1049.         break;
  1050.  
  1051.     case SRCH_ACCM:
  1052.     default:
  1053.         *pptr -= 1;
  1054.         if (*pptr < 0)
  1055.             *pptr = 0;
  1056.         pat[*pptr] = '\0';
  1057.         break;
  1058.     }
  1059.     is_pop();
  1060.     return (TRUE);
  1061. }
  1062.  
  1063. is_find(dir)
  1064. register int    dir;
  1065. {
  1066.     register int    plen;
  1067.  
  1068.     plen = strlen(pat);
  1069.     if (plen != 0) {
  1070.         if (dir==SRCH_FORW || dir==SRCH_NEXT) {
  1071.             backchar(FALSE, plen, KRANDOM);
  1072.             if (forwsrch() == FALSE) {
  1073.                 forwchar(FALSE, plen, KRANDOM);
  1074.                 return (FALSE);
  1075.             }
  1076.             return (TRUE);
  1077.         }
  1078.         if (dir==SRCH_BACK || dir==SRCH_PREV) {
  1079.             forwchar(FALSE, plen, KRANDOM);
  1080.             if (backsrch() == FALSE) {
  1081.                 backchar(FALSE, plen, KRANDOM);
  1082.                 return (FALSE);
  1083.             }
  1084.             return (TRUE);
  1085.         }
  1086.         eprintf("bad call to is_find");
  1087.         ctrlg(FALSE, 0, KRANDOM);
  1088.         return (FALSE);
  1089.     }
  1090.     return (FALSE);
  1091. }
  1092.  
  1093. /*
  1094.  * If called with "dir" not one of SRCH_FORW
  1095.  * or SRCH_BACK, this routine used to print an error
  1096.  * message. It also used to return TRUE or FALSE,
  1097.  * depending on if it liked the "dir". However, none
  1098.  * of the callers looked at the status, so I just
  1099.  * made the checking vanish.
  1100.  */
  1101. is_prompt(dir, flag, success)
  1102. {
  1103.     if (dir == SRCH_FORW) {
  1104.         if (success != FALSE)
  1105.             is_dspl("i-search forward", flag);
  1106.         else
  1107.             is_dspl("failing i-search forward", flag);
  1108.     } else if (dir == SRCH_BACK) {
  1109.         if (success != FALSE)
  1110.             is_dspl("i-search backward", flag);
  1111.         else
  1112.             is_dspl("failing i-search backward", flag);
  1113.     }
  1114. }
  1115.  
  1116. /*
  1117.  * Prompt writing routine for the incremental search. 
  1118.  * The "prompt" is just a string. The "flag" determines
  1119.  * if a "[ ]" or ":" embelishment is used.
  1120.  */
  1121. is_dspl(prompt, flag)
  1122. char    *prompt;
  1123. {
  1124.     if (flag != FALSE)
  1125.         eprintf("%s [%s]", prompt, pat);
  1126.     else
  1127.         eprintf("%s: %s", prompt, pat);
  1128. }
  1129.  
  1130. /*
  1131.  * Query Replace.
  1132.  *    Replace strings selectively.  Does a search and replace operation.
  1133.  *    A space or a comma replaces the string, a period replaces and quits,
  1134.  *    an n doesn't replace, a C-G quits.
  1135.  */
  1136. queryrepl(f, n, k)
  1137. {
  1138.     register int    s;
  1139.     char        news[NPAT];    /* replacement string        */
  1140.     register int    kludge;        /* Watch for saved line move    */
  1141.     LINE        *clp;        /* saved line pointer        */
  1142.     int        cbo;        /* offset into the saved line    */
  1143.     int        rcnt = 0;    /* Replacements made so far    */
  1144.     int        plen;        /* length of found string    */
  1145.  
  1146.     if ((s=readpattern("Old string")) != TRUE)
  1147.         return (s);
  1148.     if ((s=ereply("New string: ",news, NPAT)) == ABORT)
  1149.         return (s);
  1150.     if (s == FALSE)
  1151.         news[0] = '\0';
  1152.     eprintf("Query Replace:  [%s] -> [%s]", pat, news);
  1153.     plen = strlen(pat);
  1154.  
  1155.     /*
  1156.      * Search forward repeatedly, checking each time whether to insert
  1157.      * or not.  The "!" case makes the check always true, so it gets put
  1158.      * into a tighter loop for efficiency.
  1159.      *
  1160.      * If we change the line that is the remembered value of dot, then
  1161.      * it is possible for the remembered value to move.  This causes great
  1162.      * pain when trying to return to the non-existant line.
  1163.      *
  1164.      * possible fixes:
  1165.      * 1) put a single, relocated marker in the WINDOW structure, handled
  1166.      *    like mark.  The problem now becomes a what if two are needed...
  1167.      * 2) link markers into a list that gets updated (auto structures for
  1168.      *    the nodes)
  1169.      * 3) Expand the mark into a stack of marks and add pushmark, popmark.
  1170.      */
  1171.  
  1172.     clp = curwp->w_dotp;        /* save the return location    */
  1173.     cbo = curwp->w_doto;
  1174.     while (forwsrch() == TRUE) {
  1175.     retry:
  1176.         update();
  1177.         switch (ttgetc()) {
  1178.         case ' ':
  1179.         case ',':
  1180.             kludge = (curwp->w_dotp == clp);
  1181.             if (lreplace(plen, news, f) == FALSE)
  1182.                 return (FALSE);
  1183.             rcnt++;
  1184.             if (kludge != FALSE)
  1185.                 clp = curwp->w_dotp;
  1186.             break;
  1187.  
  1188.         case '.':
  1189.             kludge = (curwp->w_dotp == clp);
  1190.             if (lreplace(plen, news, f) == FALSE)
  1191.                 return (FALSE);
  1192.             rcnt++;
  1193.             if (kludge != FALSE)
  1194.                 clp = curwp->w_dotp;
  1195.             goto stopsearch;
  1196.  
  1197.         case CCHR('G'):
  1198.             ctrlg(FALSE, 0, KRANDOM);
  1199.             goto stopsearch;
  1200.  
  1201.         case '!':
  1202.             do {
  1203.                 kludge = (curwp->w_dotp == clp);
  1204.                 if (lreplace(plen, news, f) == FALSE)
  1205.                     return (FALSE);
  1206.                 rcnt++;
  1207.                 if (kludge != FALSE)
  1208.                     clp = curwp->w_dotp;
  1209.             } while (forwsrch() == TRUE);
  1210.             goto stopsearch;
  1211.  
  1212.         case 'n':
  1213.             break;
  1214.  
  1215.         default:
  1216. eprintf("<SP>[,] replace, [.] rep-end, [n] don't, [!] repl rest [C-G] quit");
  1217.             goto retry;
  1218.         }
  1219.     }
  1220. stopsearch:
  1221.     curwp->w_dotp = clp;
  1222.     curwp->w_doto = cbo;
  1223.     curwp->w_flag |= WFHARD;
  1224.     update();
  1225.     if (rcnt == 0)
  1226.         eprintf("[No replacements done]");
  1227.     else if (rcnt == 1)
  1228.         eprintf("[1 replacement done]");
  1229.     else
  1230.         eprintf("[%d replacements done]", rcnt);
  1231.     return (TRUE);
  1232. }
  1233.  
  1234. /*
  1235.  * This routine does the real work of a
  1236.  * forward search. The pattern is sitting in the external
  1237.  * variable "pat". If found, dot is updated, the window system
  1238.  * is notified of the change, and TRUE is returned. If the
  1239.  * string isn't found, FALSE is returned.
  1240.  */
  1241. forwsrch()
  1242. {
  1243.     register LINE    *clp;
  1244.     register int    cbo;
  1245.     register LINE    *tlp;
  1246.     register int    tbo;
  1247.     register char    *pp;
  1248.     register int    c;
  1249.  
  1250.     clp = curwp->w_dotp;
  1251.     cbo = curwp->w_doto;
  1252.     while (clp != curbp->b_linep) {
  1253.         if (cbo == llength(clp)) {
  1254.             clp = lforw(clp);
  1255.             cbo = 0;
  1256.             c = '\n';
  1257.         } else
  1258.             c = lgetc(clp, cbo++);
  1259.         if (eq(c, pat[0]) != FALSE) {
  1260.             tlp = clp;
  1261.             tbo = cbo;
  1262.             pp  = &pat[1];
  1263.             while (*pp != 0) {
  1264.                 if (tlp == curbp->b_linep)
  1265.                     goto fail;
  1266.                 if (tbo == llength(tlp)) {
  1267.                     tlp = lforw(tlp);
  1268.                     if (tlp == curbp->b_linep)
  1269.                         goto fail;
  1270.                     tbo = 0;
  1271.                     c = '\n';
  1272.                 } else
  1273.                     c = lgetc(tlp, tbo++);
  1274.                 if (eq(c, *pp++) == FALSE)
  1275.                     goto fail;
  1276.             }
  1277.             curwp->w_dotp  = tlp;
  1278.             curwp->w_doto  = tbo;
  1279.             curwp->w_flag |= WFMOVE;
  1280.             return (TRUE);
  1281.         }
  1282.     fail:    ;
  1283.     }
  1284.     return (FALSE);
  1285. }
  1286.  
  1287. /*
  1288.  * This routine does the real work of a
  1289.  * backward search. The pattern is sitting in the external
  1290.  * variable "pat". If found, dot is updated, the window system
  1291.  * is notified of the change, and TRUE is returned. If the
  1292.  * string isn't found, FALSE is returned.
  1293.  */
  1294. backsrch()
  1295. {
  1296.     register LINE    *clp;
  1297.     register int    cbo;
  1298.     register LINE    *tlp;
  1299.     register int    tbo;
  1300.     register int    c;
  1301.     register char    *epp;
  1302.     register char    *pp;
  1303.  
  1304.     for (epp = &pat[0]; epp[1] != 0; ++epp)
  1305.         ;
  1306.     clp = curwp->w_dotp;
  1307.     cbo = curwp->w_doto;
  1308.     for (;;) {
  1309.         if (cbo == 0) {
  1310.             clp = lback(clp);
  1311.             if (clp == curbp->b_linep)
  1312.                 return (FALSE);
  1313.             cbo = llength(clp)+1;
  1314.         }
  1315.         if (--cbo == llength(clp))
  1316.             c = '\n';
  1317.         else
  1318.             c = lgetc(clp,cbo);
  1319.         if (eq(c, *epp) != FALSE) {
  1320.             tlp = clp;
  1321.             tbo = cbo;
  1322.             pp  = epp;
  1323.             while (pp != &pat[0]) {
  1324.                 if (tbo == 0) {
  1325.                     tlp = lback(tlp);
  1326.                     if (tlp == curbp->b_linep)
  1327.                         goto fail;
  1328.                     tbo = llength(tlp)+1;
  1329.                 }
  1330.                 if (--tbo == llength(tlp))
  1331.                     c = '\n';
  1332.                 else
  1333.                     c = lgetc(tlp,tbo);
  1334.                 if (eq(c, *--pp) == FALSE)
  1335.                     goto fail;
  1336.             }
  1337.             curwp->w_dotp  = tlp;
  1338.             curwp->w_doto  = tbo;
  1339.             curwp->w_flag |= WFMOVE;
  1340.             return (TRUE);
  1341.         }
  1342.     fail:    ;
  1343.     }
  1344. }
  1345.  
  1346. /*
  1347.  * Compare two characters.
  1348.  * The "bc" comes from the buffer.
  1349.  * It has its case folded out. The
  1350.  * "pc" is from the pattern.
  1351.  */
  1352. eq(bc, pc)
  1353. {
  1354.     register int    ibc;
  1355.     register int    ipc;
  1356.  
  1357.     ibc = bc & 0xFF;
  1358.     ipc = pc & 0xFF;
  1359.     if (ISLOWER(ibc) != FALSE)
  1360.         ibc = TOUPPER(ibc);
  1361.     if (ISLOWER(ipc) != FALSE)
  1362.         ipc = TOUPPER(ipc);
  1363.     if (ibc == ipc)
  1364.         return (TRUE);
  1365.     return (FALSE);
  1366. }
  1367.  
  1368. /*
  1369.  * Read a pattern.
  1370.  * Stash it in the external variable "pat". The "pat" is
  1371.  * not updated if the user types in an empty line. If the user typed
  1372.  * an empty line, and there is no old pattern, it is an error.
  1373.  * Display the old pattern, in the style of Jeff Lomicka. There is
  1374.  * some do-it-yourself control expansion.
  1375.  */
  1376. readpattern(prompt)
  1377. char    *prompt;
  1378. {
  1379.     register int    s;
  1380.     char        tpat[NPAT];
  1381.  
  1382.     s = ereply("%s [%s]: ", tpat, NPAT, prompt, pat);
  1383.     if (s == TRUE)                /* Specified        */
  1384.         strcpy(pat, tpat);
  1385.     else if (s==FALSE && pat[0]!=0)        /* CR, but old one    */
  1386.         s = TRUE;
  1387.     return (s);
  1388. }
  1389. SHAR_EOF
  1390. if test 14284 -ne "`wc -c < 'search.c'`"
  1391. then
  1392.     echo shar: error transmitting "'search.c'" '(should have been 14284 characters)'
  1393. fi
  1394. fi
  1395. echo shar: extracting "'symbol.c'" '(10576 characters)'
  1396. if test -f 'symbol.c'
  1397. then
  1398.     echo shar: will not over-write existing file "'symbol.c'"
  1399. else
  1400. cat << \SHAR_EOF > 'symbol.c'
  1401. /*
  1402.  * Name:    MicroEMACS
  1403.  *        Symbol table stuff.
  1404.  * Version:    29
  1405.  * Last edit:    05-Feb-86
  1406.  * By:        rex::conroy
  1407.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  1408.  *
  1409.  * Symbol tables, and keymap setup.
  1410.  * The terminal specific parts of building the
  1411.  * keymap has been moved to a better place.
  1412.  */
  1413. #include    "def.h"
  1414.  
  1415. #define    DIRLIST    0            /* Disarmed!            */
  1416.  
  1417. /*
  1418.  * Defined by "main.c".
  1419.  */
  1420. extern    int    ctrlg();        /* Abort out of things        */
  1421. extern    int    quit();            /* Quit                */
  1422. extern    int    ctlxlp();        /* Begin macro            */
  1423. extern    int    ctlxrp();        /* End macro            */
  1424. extern    int    ctlxe();        /* Execute macro        */
  1425. extern    int    jeffexit();        /* Jeff Lomicka style exit.    */
  1426. extern  int    showversion();        /* Show version numbers, etc.    */
  1427.  
  1428. /*
  1429.  * Defined by "search.c".
  1430.  */
  1431. extern    int    forwsearch();        /* Search forward        */
  1432. extern    int    backsearch();        /* Search backwards        */
  1433. extern  int    searchagain();        /* Repeat last search command    */
  1434. extern  int    forwisearch();        /* Incremental search forward    */
  1435. extern  int    backisearch();        /* Incremental search backwards    */
  1436. extern  int    queryrepl();        /* Query replace        */
  1437.  
  1438. /*
  1439.  * Defined by "basic.c".
  1440.  */
  1441. extern    int    gotobol();        /* Move to start of line    */
  1442. extern    int    backchar();        /* Move backward by characters    */
  1443. extern    int    gotoeol();        /* Move to end of line        */
  1444. extern    int    forwchar();        /* Move forward by characters    */
  1445. extern    int    gotobob();        /* Move to start of buffer    */
  1446. extern    int    gotoeob();        /* Move to end of buffer    */
  1447. extern    int    forwline();        /* Move forward by lines    */
  1448. extern    int    backline();        /* Move backward by lines    */
  1449. extern    int    forwpage();        /* Move forward by pages    */
  1450. extern    int    backpage();        /* Move backward by pages    */
  1451. extern    int    setmark();        /* Set mark            */
  1452. extern    int    swapmark();        /* Swap "." and mark        */
  1453. extern    int    gotoline();        /* Go to a specified line.    */
  1454.  
  1455. /*
  1456.  * Defined by "buffer.c".
  1457.  */
  1458. extern    int    listbuffers();        /* Display list of buffers    */
  1459. extern    int    usebuffer();        /* Switch a window to a buffer    */
  1460. extern    int    killbuffer();        /* Make a buffer go away.    */
  1461.  
  1462. #if    DIRLIST
  1463. /*
  1464.  * Defined by "dirlist.c".
  1465.  */
  1466. extern    int    dirlist();        /* Directory list.        */
  1467. #endif
  1468.  
  1469. /*
  1470.  * Defined by "display.c".
  1471.  */
  1472. extern  int    readmsg();        /* Read next line of message.    */
  1473.  
  1474. /*
  1475.  * Defined by "file.c".
  1476.  */
  1477. extern    int    fileread();        /* Get a file, read only    */
  1478. extern    int    filevisit();        /* Get a file, read write    */
  1479. extern    int    filewrite();        /* Write a file            */
  1480. extern    int    filesave();        /* Save current file        */
  1481. extern    int    filename();        /* Adjust file name        */
  1482.  
  1483. /*
  1484.  * Defined by "random.c".
  1485.  */
  1486. extern    int    selfinsert();        /* Insert character        */
  1487. extern    int    showcpos();        /* Show the cursor position    */
  1488. extern    int    twiddle();        /* Twiddle characters        */
  1489. extern    int    quote();        /* Insert literal        */
  1490. extern    int    openline();        /* Open up a blank line        */
  1491. extern    int    newline();        /* Insert CR-LF            */
  1492. extern    int    deblank();        /* Delete blank lines        */
  1493. extern    int    indent();        /* Insert CR-LF, then indent    */
  1494. extern    int    forwdel();        /* Forward delete        */
  1495. extern    int    backdel();        /* Backward delete        */
  1496. extern    int    killline();        /* Kill forward            */
  1497. extern    int    yank();            /* Yank back from killbuffer.    */
  1498.  
  1499. /*
  1500.  * Defined by "region.c".
  1501.  */
  1502. extern    int    killregion();        /* Kill region.            */
  1503. extern    int    copyregion();        /* Copy region to kill buffer.    */
  1504. extern    int    lowerregion();        /* Lower case region.        */
  1505. extern    int    upperregion();        /* Upper case region.        */
  1506.  
  1507. /*
  1508.  * Defined by "spawn.c".
  1509.  */
  1510. extern    int    spawncli();        /* Run CLI in a subjob.        */
  1511.  
  1512. /*
  1513.  * Defined by "window.c".
  1514.  */
  1515. extern    int    reposition();        /* Reposition window        */
  1516. extern    int    refresh();        /* Refresh the screen        */
  1517. extern    int    nextwind();        /* Move to the next window    */
  1518. extern  int    prevwind();        /* Move to the previous window    */
  1519. extern    int    mvdnwind();        /* Move window down        */
  1520. extern    int    mvupwind();        /* Move window up        */
  1521. extern    int    onlywind();        /* Make current window only one    */
  1522. extern    int    splitwind();        /* Split current window        */
  1523. extern    int    enlargewind();        /* Enlarge display window.    */
  1524. extern    int    shrinkwind();        /* Shrink window.        */
  1525.  
  1526. /*
  1527.  * Defined by "word.c".
  1528.  */
  1529. extern    int    backword();        /* Backup by words        */
  1530. extern    int    forwword();        /* Advance by words        */
  1531. extern    int    upperword();        /* Upper case word.        */
  1532. extern    int    lowerword();        /* Lower case word.        */
  1533. extern    int    capword();        /* Initial capitalize word.    */
  1534. extern    int    delfword();        /* Delete forward word.        */
  1535. extern    int    delbword();        /* Delete backward word.    */
  1536.  
  1537. /*
  1538.  * Defined by "extend.c".
  1539.  */
  1540. extern    int    extend();        /* Extended commands.        */
  1541. extern    int    help();            /* Help key.            */
  1542. extern    int    bindtokey();        /* Modify key bindings.        */
  1543. extern    int    wallchart();        /* Make wall chart.        */
  1544.  
  1545. typedef    struct    {
  1546.     short    k_key;            /* Key to bind.            */
  1547.     int    (*k_funcp)();        /* Function.            */
  1548.     char    *k_name;        /* Function name string.    */
  1549. }    KEY;
  1550.  
  1551. /*
  1552.  * Default key binding table. This contains
  1553.  * the function names, the symbol table name, and (possibly)
  1554.  * a key binding for the builtin functions. There are no
  1555.  * bindings for C-U or C-X. These are done with special
  1556.  * code, but should be done normally.
  1557.  */
  1558. KEY    key[] = {
  1559.     KCTRL|'@',    setmark,    "set-mark",
  1560.     KCTRL|'A',    gotobol,    "goto-bol",
  1561.     KCTRL|'B',    backchar,    "back-char",
  1562.     KCTRL|'C',    spawncli,    "spawn-cli",
  1563.     KCTRL|'D',    forwdel,    "forw-del-char",
  1564.     KCTRL|'E',    gotoeol,    "goto-eol",
  1565.     KCTRL|'F',    forwchar,    "forw-char",
  1566.     KCTRL|'G',    ctrlg,        "abort",
  1567.     KCTRL|'H',    backdel,    "back-del-char",
  1568.     KCTRL|'I',    selfinsert,    "ins-self",
  1569.     KCTRL|'J',    indent,        "ins-nl-and-indent",
  1570.     KCTRL|'K',    killline,    "kill-line",
  1571.     KCTRL|'L',    refresh,    "refresh",
  1572.     KCTRL|'M',    newline,    "ins-nl",
  1573.     KCTRL|'N',    forwline,    "forw-line",
  1574.     KCTRL|'O',    openline,    "ins-nl-and-backup",
  1575.     KCTRL|'P',    backline,    "back-line",
  1576.     KCTRL|'Q',    quote,        "quote",
  1577.     KCTRL|'R',    backisearch,    "back-i-search",
  1578.     KCTRL|'S',    forwisearch,    "forw-i-search",
  1579.     KCTRL|'T',    twiddle,    "twiddle",
  1580.     KCTRL|'V',    forwpage,    "forw-page",
  1581.     KCTRL|'W',    killregion,    "kill-region",
  1582.     KCTRL|'Y',    yank,        "yank",
  1583.     KCTRL|'Z',    jeffexit,    "jeff-exit",
  1584.     KCTLX|KCTRL|'B',listbuffers,    "display-buffers",
  1585.     KCTLX|KCTRL|'C',quit,        "quit",
  1586. #if    DIRLIST
  1587.     KCTLX|KCTRL|'D',dirlist,    "display-directory",
  1588. #endif
  1589.     KCTLX|KCTRL|'F',filename,    "set-file-name",
  1590.     KCTLX|KCTRL|'L',lowerregion,    "lower-region",
  1591.     KCTLX|KCTRL|'N',mvdnwind,    "down-window",
  1592.     KCTLX|KCTRL|'O',deblank,    "del-blank-lines",
  1593.     KCTLX|KCTRL|'P',mvupwind,    "up-window",
  1594.     KCTLX|KCTRL|'R',fileread,    "file-read",
  1595.     KCTLX|KCTRL|'S',filesave,    "file-save",
  1596.     KCTLX|KCTRL|'U',upperregion,    "upper-region",
  1597.     KCTLX|KCTRL|'V',filevisit,    "file-visit",
  1598.     KCTLX|KCTRL|'W',filewrite,    "file-write",
  1599.     KCTLX|KCTRL|'X',swapmark,    "swap-dot-and-mark",
  1600.     KCTLX|KCTRL|'Z',shrinkwind,    "shrink-window",
  1601.     KCTLX|'=',    showcpos,    "display-position",
  1602.     KCTLX|'(',    ctlxlp,        "start-macro",
  1603.     KCTLX|')',    ctlxrp,        "end-macro",
  1604.     KCTLX|'1',    onlywind,    "only-window",
  1605.     KCTLX|'2',    splitwind,    "split-window",
  1606.     KCTLX|'B',    usebuffer,    "use-buffer",
  1607.     KCTLX|'E',    ctlxe,        "execute-macro",
  1608.     KCTLX|'G',    gotoline,    "goto-line",
  1609.     KCTLX|'K',    killbuffer,    "kill-buffer",
  1610.     KCTLX|'N',    nextwind,    "forw-window",
  1611.     KCTLX|'P',    prevwind,    "back-window",
  1612.     KCTLX|'Z',    enlargewind,    "enlarge-window",
  1613.     KMETA|KCTRL|'H',delbword,    "back-del-word",
  1614.     KMETA|KCTRL|'R',readmsg,    "display-message",
  1615.     KMETA|KCTRL|'V',showversion,    "display-version",
  1616.     KMETA|'!',    reposition,    "reposition-window",
  1617.     KMETA|'>',    gotoeob,    "goto-eob",
  1618.     KMETA|'<',    gotobob,    "goto-bob",
  1619.     KMETA|'%',    queryrepl,    "query-replace",
  1620.     KMETA|'B',    backword,    "back-word",
  1621.     KMETA|'C',    capword,    "cap-word",
  1622.     KMETA|'D',    delfword,    "forw-del-word",
  1623.     KMETA|'F',    forwword,    "forw-word",
  1624.     KMETA|'L',    lowerword,    "lower-word",
  1625.     KMETA|'R',    backsearch,    "back-search",
  1626.     KMETA|'S',    forwsearch,    "forw-search",
  1627.     KMETA|'U',    upperword,    "upper-word",
  1628.     KMETA|'V',    backpage,    "back-page",
  1629.     KMETA|'W',    copyregion,    "copy-region",
  1630.     KMETA|'X',    extend,        "extended-command",
  1631.     -1,        searchagain,    "search-again",
  1632.     -1,        help,        "help",
  1633.     -1,        wallchart,    "display-bindings",
  1634.     -1,        bindtokey,    "bind-to-key"
  1635. };
  1636.  
  1637. #define    NKEY    (sizeof(key) / sizeof(key[0]))
  1638.  
  1639. /*
  1640.  * Symbol table lookup.
  1641.  * Return a pointer to the SYMBOL node, or NULL if
  1642.  * the symbol is not found.
  1643.  */
  1644. SYMBOL    *
  1645. symlookup(cp)
  1646. register char    *cp;
  1647. {
  1648.     register SYMBOL    *sp;
  1649.  
  1650.     sp = symbol[symhash(cp)];
  1651.     while (sp != NULL) {
  1652.         if (strcmp(cp, sp->s_name) == 0)
  1653.             return (sp);
  1654.         sp = sp->s_symp;
  1655.     }
  1656.     return (NULL);
  1657. }
  1658.  
  1659. /*
  1660.  * Take a string, and compute the symbol table
  1661.  * bucket number. This is done by adding all of the characters
  1662.  * together, and taking the sum mod NSHASH. The string probably
  1663.  * should not contain any GR characters; if it does the "*cp"
  1664.  * may get a nagative number on some machines, and the "%"
  1665.  * will return a negative number!
  1666.  */
  1667. symhash(cp)
  1668. register char    *cp;
  1669. {
  1670.     register int    c;
  1671.     register int    n;
  1672.  
  1673.     n = 0;
  1674.     while ((c = *cp++) != 0)
  1675.         n += c;
  1676.     return (n % NSHASH);
  1677. }
  1678.  
  1679. /*
  1680.  * Build initial keymap. The funny keys
  1681.  * (commands, odd control characters) are mapped using
  1682.  * a big table and calls to "keyadd". The printing characters
  1683.  * are done with some do-it-yourself handwaving. The terminal
  1684.  * specific keymap initialization code is called at the
  1685.  * very end to finish up. All errors are fatal.
  1686.  */
  1687. keymapinit()
  1688. {
  1689.     register SYMBOL    *sp;
  1690.     register KEY    *kp;
  1691.     register int    i;
  1692.     register int    hash;
  1693.  
  1694.     for (i=0; i<NKEYS; ++i)
  1695.         binding[i] = NULL;
  1696.     for (kp = &key[0]; kp < &key[NKEY]; ++kp)
  1697.         keyadd(kp->k_key, kp->k_funcp, kp->k_name);
  1698.     keydup(KCTLX|KCTRL|'G',    "abort");
  1699.     keydup(KMETA|KCTRL|'G',    "abort");
  1700.     keydup(0x7F,        "back-del-char");
  1701.     keydup(KCTLX|'R',    "back-i-search");
  1702.     keydup(KCTLX|'S',    "forw-i-search");
  1703.     keydup(KMETA|'.',    "set-mark");
  1704.     keydup(KMETA|'Q',    "quote");
  1705.     keydup(KMETA|0x7F,    "back-del-word");
  1706.     /*
  1707.      * Should be bound by "tab" already.
  1708.      */
  1709.     if ((sp=symlookup("ins-self")) == NULL)
  1710.         abort();
  1711.     for (i=0x20; i<0x7F; ++i) {
  1712.         if (binding[i] != NULL)
  1713.             abort();
  1714.         binding[i] = sp;
  1715.         ++sp->s_nkey;
  1716.     }
  1717.     ttykeymapinit();
  1718. }
  1719.  
  1720. /*
  1721.  * Create a new builtin function "name"
  1722.  * with function "funcp". If the "new" is a real
  1723.  * key, bind it as a side effect. All errors
  1724.  * are fatal.
  1725.  */
  1726. keyadd(new, funcp, name)
  1727. int    (*funcp)();
  1728. char    *name;
  1729. {
  1730.     register SYMBOL    *sp;
  1731.     register int    hash;
  1732.  
  1733.     if ((sp=(SYMBOL *)malloc(sizeof(SYMBOL))) == NULL)
  1734.         abort();
  1735.     hash = symhash(name);
  1736.     sp->s_symp = symbol[hash];
  1737.     symbol[hash] = sp;
  1738.     sp->s_nkey = 0;
  1739.     sp->s_name = name;
  1740.     sp->s_funcp = funcp;
  1741.     if (new >= 0) {                /* Bind this key.    */
  1742.         if (binding[new] != NULL)
  1743.             abort();
  1744.         binding[new] = sp;
  1745.         ++sp->s_nkey;
  1746.     }
  1747. }
  1748.  
  1749. /*
  1750.  * Bind key "new" to the existing
  1751.  * routine "name". If the name cannot be found,
  1752.  * or the key is already bound, abort.
  1753.  */
  1754. keydup(new, name)
  1755. register int    new;
  1756. char        *name;
  1757. {
  1758.     register SYMBOL    *sp;
  1759.  
  1760.     if (binding[new]!=NULL || (sp=symlookup(name))==NULL)
  1761.         abort();
  1762.     binding[new] = sp;
  1763.     ++sp->s_nkey;
  1764. }
  1765. SHAR_EOF
  1766. if test 10576 -ne "`wc -c < 'symbol.c'`"
  1767. then
  1768.     echo shar: error transmitting "'symbol.c'" '(should have been 10576 characters)'
  1769. fi
  1770. fi
  1771. echo shar: extracting "'version.c'" '(600 characters)'
  1772. if test -f 'version.c'
  1773. then
  1774.     echo shar: will not over-write existing file "'version.c'"
  1775. else
  1776. cat << \SHAR_EOF > 'version.c'
  1777. /*
  1778.  * Name:    MicroEMACS
  1779.  *        Version stamp.
  1780.  * Version:    30
  1781.  * Last edit:    14-Feb-86
  1782.  * By:        rex::conroy
  1783.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  1784.  *
  1785.  * This file contains the string(s)
  1786.  * that get written out by the show version command.
  1787.  * Rich had it generated by a command file. I do
  1788.  * it manually, until I can figure out a way to get
  1789.  * the MicroEMACS version number generated in a
  1790.  * reasonable (automatic) manner. Perhaps a program
  1791.  * that reads "things2do.txt".
  1792.  */
  1793. #include    "def.h"
  1794.  
  1795. char    *version[] = {
  1796.     "MicroEMACS version 30",
  1797.     "Source from REX::USER$A:[CONROY.HACKING.MINIEMACS]",
  1798.     NULL
  1799. }; 
  1800. SHAR_EOF
  1801. if test 600 -ne "`wc -c < 'version.c'`"
  1802. then
  1803.     echo shar: error transmitting "'version.c'" '(should have been 600 characters)'
  1804. fi
  1805. fi
  1806. echo shar: extracting "'window.c'" '(9891 characters)'
  1807. if test -f 'window.c'
  1808. then
  1809.     echo shar: will not over-write existing file "'window.c'"
  1810. else
  1811. cat << \SHAR_EOF > 'window.c'
  1812. /*
  1813.  * Name:    MicroEMACS
  1814.  *        Window handling.
  1815.  * Version:    29
  1816.  * Last edit:    10-Feb-86
  1817.  * By:        rex::conroy
  1818.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  1819.  */
  1820. #include    "def.h"
  1821.  
  1822. /*
  1823.  * Reposition dot in the current
  1824.  * window to line "n". If the argument is
  1825.  * positive, it is that line. If it is negative it
  1826.  * is that line from the bottom. If it is 0 the window
  1827.  * is centered (this is what the standard redisplay code
  1828.  * does). With no argument it defaults to 1.
  1829.  * Because of the default, it works like in
  1830.  * Gosling.
  1831.  */
  1832. reposition(f, n, k)
  1833. {
  1834.     curwp->w_force = n;
  1835.     curwp->w_flag |= WFFORCE;
  1836.     return (TRUE);
  1837. }
  1838.  
  1839. /*
  1840.  * Refresh the display. A call is made to the
  1841.  * "ttresize" entry in the terminal handler, which tries
  1842.  * to reset "nrow" and "ncol". They will, however, never
  1843.  * be set outside of the NROW or NCOL range. If the display
  1844.  * changed size, arrange that everything is redone, then
  1845.  * call "update" to fix the display. We do this so the
  1846.  * new size can be displayed. In the normal case the
  1847.  * call to "update" in "main.c" refreshes the screen,
  1848.  * and all of the windows need not be recomputed.
  1849.  * Note that when you get to the "display unusable"
  1850.  * message, the screen will be messed up. If you make
  1851.  * the window bigger again, and send another command,
  1852.  * everything will get fixed!
  1853.  */
  1854. refresh(f, n, k)
  1855. {
  1856.     register WINDOW    *wp;
  1857.     register int    oldnrow;
  1858.     register int    oldncol;
  1859.  
  1860.     oldnrow = nrow;
  1861.     oldncol = ncol;
  1862.     ttresize();
  1863.     if (nrow!=oldnrow || ncol!=oldncol) {
  1864.         wp = wheadp;            /* Find last.        */
  1865.         while (wp->w_wndp != NULL)
  1866.             wp = wp->w_wndp;
  1867.         if (nrow < wp->w_toprow+3) {    /* Check if too small.    */
  1868.             eprintf("Display unusable");
  1869.             return (FALSE);
  1870.         }        
  1871.         wp->w_ntrows = nrow-wp->w_toprow-2;
  1872.         wp = wheadp;            /* Redraw all.        */
  1873.         while (wp != NULL) {
  1874.             wp->w_flag |= WFMODE|WFHARD;
  1875.             wp = wp->w_wndp;
  1876.         }
  1877.         sgarbf = TRUE;
  1878.         update();
  1879.         eprintf("[New size %d by %d]", nrow, ncol);
  1880.     } else
  1881.         sgarbf = TRUE;
  1882.     return (TRUE);
  1883. }
  1884.  
  1885. /*
  1886.  * The command make the next
  1887.  * window (next => down the screen)
  1888.  * the current window. There are no real
  1889.  * errors, although the command does
  1890.  * nothing if there is only 1 window on
  1891.  * the screen.
  1892.  */
  1893. nextwind(f, n, k)
  1894. {
  1895.     register WINDOW    *wp;
  1896.  
  1897.     if ((wp=curwp->w_wndp) == NULL)
  1898.         wp = wheadp;
  1899.     curwp = wp;
  1900.     curbp = wp->w_bufp;
  1901.     return (TRUE);
  1902. }
  1903.  
  1904. /*
  1905.  * This command makes the previous
  1906.  * window (previous => up the screen) the
  1907.  * current window. There arn't any errors,
  1908.  * although the command does not do a lot
  1909.  * if there is 1 window.
  1910.  */
  1911. prevwind(f, n, k)
  1912. {
  1913.     register WINDOW    *wp1;
  1914.     register WINDOW    *wp2;
  1915.  
  1916.     wp1 = wheadp;
  1917.     wp2 = curwp;
  1918.     if (wp1 == wp2)
  1919.         wp2 = NULL;
  1920.     while (wp1->w_wndp != wp2)
  1921.         wp1 = wp1->w_wndp;
  1922.     curwp = wp1;
  1923.     curbp = wp1->w_bufp;
  1924.     return (TRUE);
  1925. }
  1926.  
  1927. /*
  1928.  * This command moves the current
  1929.  * window down by "arg" lines. Recompute
  1930.  * the top line in the window. The move up and
  1931.  * move down code is almost completely the same;
  1932.  * most of the work has to do with reframing the
  1933.  * window, and picking a new dot. We share the
  1934.  * code by having "move down" just be an interface
  1935.  * to "move up".
  1936.  */
  1937. mvdnwind(f, n, k)
  1938. register int    n;
  1939. {
  1940.     return (mvupwind(f, -n, KRANDOM));
  1941. }
  1942.  
  1943. /*
  1944.  * Move the current window up by "arg"
  1945.  * lines. Recompute the new top line of the window.
  1946.  * Look to see if "." is still on the screen. If it is,
  1947.  * you win. If it isn't, then move "." to center it
  1948.  * in the new framing of the window (this command does
  1949.  * not really move "."; it moves the frame).
  1950.  */
  1951. mvupwind(f, n, k)
  1952. register int    n;
  1953. {
  1954.     register LINE    *lp;
  1955.     register int    i;
  1956.  
  1957.     lp = curwp->w_linep;
  1958.     if (n < 0) {
  1959.         while (n++ && lp!=curbp->b_linep)
  1960.             lp = lforw(lp);
  1961.     } else {
  1962.         while (n-- && lback(lp)!=curbp->b_linep)
  1963.             lp = lback(lp);
  1964.     }
  1965.     curwp->w_linep = lp;
  1966.     curwp->w_flag |= WFHARD;        /* Mode line is OK.    */
  1967.     for (i=0; i<curwp->w_ntrows; ++i) {
  1968.         if (lp == curwp->w_dotp)
  1969.             return (TRUE);
  1970.         if (lp == curbp->b_linep)
  1971.             break;
  1972.         lp = lforw(lp);
  1973.     }
  1974.     lp = curwp->w_linep;
  1975.     i  = curwp->w_ntrows/2;
  1976.     while (i-- && lp!=curbp->b_linep)
  1977.         lp = lforw(lp);
  1978.     curwp->w_dotp  = lp;
  1979.     curwp->w_doto  = 0;
  1980.     return (TRUE);
  1981. }
  1982.  
  1983. /*
  1984.  * This command makes the current
  1985.  * window the only window on the screen.
  1986.  * Try to set the framing
  1987.  * so that "." does not have to move on
  1988.  * the display. Some care has to be taken
  1989.  * to keep the values of dot and mark
  1990.  * in the buffer structures right if the
  1991.  * distruction of a window makes a buffer
  1992.  * become undisplayed.
  1993.  */
  1994. onlywind(f, n, k)
  1995. {
  1996.     register WINDOW    *wp;
  1997.     register LINE    *lp;
  1998.     register int    i;
  1999.  
  2000.     while (wheadp != curwp) {
  2001.         wp = wheadp;
  2002.         wheadp = wp->w_wndp;
  2003.         if (--wp->w_bufp->b_nwnd == 0) {
  2004.             wp->w_bufp->b_dotp  = wp->w_dotp;
  2005.             wp->w_bufp->b_doto  = wp->w_doto;
  2006.             wp->w_bufp->b_markp = wp->w_markp;
  2007.             wp->w_bufp->b_marko = wp->w_marko;
  2008.         }
  2009.         free((char *) wp);
  2010.     }
  2011.     while (curwp->w_wndp != NULL) {
  2012.         wp = curwp->w_wndp;
  2013.         curwp->w_wndp = wp->w_wndp;
  2014.         if (--wp->w_bufp->b_nwnd == 0) {
  2015.             wp->w_bufp->b_dotp  = wp->w_dotp;
  2016.             wp->w_bufp->b_doto  = wp->w_doto;
  2017.             wp->w_bufp->b_markp = wp->w_markp;
  2018.             wp->w_bufp->b_marko = wp->w_marko;
  2019.         }
  2020.         free((char *) wp);
  2021.     }
  2022.     lp = curwp->w_linep;
  2023.     i  = curwp->w_toprow;
  2024.     while (i!=0 && lback(lp)!=curbp->b_linep) {
  2025.         --i;
  2026.         lp = lback(lp);
  2027.     }
  2028.     curwp->w_toprow = 0;
  2029.     curwp->w_ntrows = nrow-2;        /* 2 = mode, echo.    */
  2030.     curwp->w_linep  = lp;
  2031.     curwp->w_flag  |= WFMODE|WFHARD;
  2032.     return (TRUE);
  2033. }
  2034.  
  2035. /*
  2036.  * Split the current window. A window
  2037.  * smaller than 3 lines cannot be split.
  2038.  * The only other error that is possible is
  2039.  * a "malloc" failure allocating the structure
  2040.  * for the new window.
  2041.  */
  2042. splitwind(f, n, k)
  2043. {
  2044.     register WINDOW    *wp;
  2045.     register LINE    *lp;
  2046.     register int    ntru;
  2047.     register int    ntrl;
  2048.     register int    ntrd;
  2049.     register WINDOW    *wp1;
  2050.     register WINDOW    *wp2;
  2051.  
  2052.     if (curwp->w_ntrows < 3) {
  2053.         eprintf("Cannot split a %d line window", curwp->w_ntrows);
  2054.         return (FALSE);
  2055.     }
  2056.     if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
  2057.         eprintf("Cannot allocate WINDOW block");
  2058.         return (FALSE);
  2059.     }
  2060.     ++curbp->b_nwnd;            /* Displayed twice.    */
  2061.     wp->w_bufp  = curbp;
  2062.     wp->w_dotp  = curwp->w_dotp;
  2063.     wp->w_doto  = curwp->w_doto;
  2064.     wp->w_markp = curwp->w_markp;
  2065.     wp->w_marko = curwp->w_marko;
  2066.     wp->w_flag  = 0;
  2067.     wp->w_force = 0;
  2068.     ntru = (curwp->w_ntrows-1) / 2;        /* Upper size        */
  2069.     ntrl = (curwp->w_ntrows-1) - ntru;    /* Lower size        */
  2070.     lp = curwp->w_linep;
  2071.     ntrd = 0;
  2072.     while (lp != curwp->w_dotp) {
  2073.         ++ntrd;
  2074.         lp = lforw(lp);
  2075.     }
  2076.     lp = curwp->w_linep;
  2077.     if (ntrd <= ntru) {            /* Old is upper window.    */
  2078.         if (ntrd == ntru)        /* Hit mode line.    */
  2079.             lp = lforw(lp);
  2080.         curwp->w_ntrows = ntru;
  2081.         wp->w_wndp = curwp->w_wndp;
  2082.         curwp->w_wndp = wp;
  2083.         wp->w_toprow = curwp->w_toprow+ntru+1;
  2084.         wp->w_ntrows = ntrl;
  2085.     } else {                /* Old is lower window    */
  2086.         wp1 = NULL;
  2087.         wp2 = wheadp;
  2088.         while (wp2 != curwp) {
  2089.             wp1 = wp2;
  2090.             wp2 = wp2->w_wndp;
  2091.         }
  2092.         if (wp1 == NULL)
  2093.             wheadp = wp;
  2094.         else
  2095.             wp1->w_wndp = wp;
  2096.         wp->w_wndp   = curwp;
  2097.         wp->w_toprow = curwp->w_toprow;
  2098.         wp->w_ntrows = ntru;
  2099.         ++ntru;                /* Mode line.        */
  2100.         curwp->w_toprow += ntru;
  2101.         curwp->w_ntrows  = ntrl;
  2102.         while (ntru--)
  2103.             lp = lforw(lp);
  2104.     }
  2105.     curwp->w_linep = lp;            /* Adjust the top lines    */
  2106.     wp->w_linep = lp;            /* if necessary.    */
  2107.     curwp->w_flag |= WFMODE|WFHARD;
  2108.     wp->w_flag |= WFMODE|WFHARD;
  2109.     return (TRUE);
  2110. }
  2111.  
  2112. /*
  2113.  * Enlarge the current window.
  2114.  * Find the window that loses space. Make
  2115.  * sure it is big enough. If so, hack the window
  2116.  * descriptions, and ask redisplay to do all the
  2117.  * hard work. You don't just set "force reframe"
  2118.  * because dot would move.
  2119.  */
  2120. enlargewind(f, n, k)
  2121. {
  2122.     register WINDOW    *adjwp;
  2123.     register LINE    *lp;
  2124.     register int    i;
  2125.  
  2126.     if (n < 0)
  2127.         return (shrinkwind(f, -n, KRANDOM));
  2128.     if (wheadp->w_wndp == NULL) {
  2129.         eprintf("Only one window");
  2130.         return (FALSE);
  2131.     }
  2132.     if ((adjwp=curwp->w_wndp) == NULL) {
  2133.         adjwp = wheadp;
  2134.         while (adjwp->w_wndp != curwp)
  2135.             adjwp = adjwp->w_wndp;
  2136.     }
  2137.     if (adjwp->w_ntrows <= n) {
  2138.         eprintf("Impossible change");
  2139.         return (FALSE);
  2140.     }
  2141.     if (curwp->w_wndp == adjwp) {        /* Shrink below.    */
  2142.         lp = adjwp->w_linep;
  2143.         for (i=0; i<n && lp!=adjwp->w_bufp->b_linep; ++i)
  2144.             lp = lforw(lp);
  2145.         adjwp->w_linep  = lp;
  2146.         adjwp->w_toprow += n;
  2147.     } else {                /* Shrink above.    */
  2148.         lp = curwp->w_linep;
  2149.         for (i=0; i<n && lback(lp)!=curbp->b_linep; ++i)
  2150.             lp = lback(lp);
  2151.         curwp->w_linep  = lp;
  2152.         curwp->w_toprow -= n;
  2153.     }
  2154.     curwp->w_ntrows += n;
  2155.     adjwp->w_ntrows -= n;
  2156.     curwp->w_flag |= WFMODE|WFHARD;
  2157.     adjwp->w_flag |= WFMODE|WFHARD;
  2158.     return (TRUE);
  2159. }
  2160.  
  2161. /*
  2162.  * Shrink the current window.
  2163.  * Find the window that gains space. Hack at
  2164.  * the window descriptions. Ask the redisplay to
  2165.  * do all the hard work.
  2166.  */
  2167. shrinkwind(f, n, k)
  2168. {
  2169.     register WINDOW    *adjwp;
  2170.     register LINE    *lp;
  2171.     register int    i;
  2172.  
  2173.     if (n < 0)
  2174.         return (enlargewind(f, -n, KRANDOM));
  2175.     if (wheadp->w_wndp == NULL) {
  2176.         eprintf("Only one window");
  2177.         return (FALSE);
  2178.     }
  2179.     if ((adjwp=curwp->w_wndp) == NULL) {
  2180.         adjwp = wheadp;
  2181.         while (adjwp->w_wndp != curwp)
  2182.             adjwp = adjwp->w_wndp;
  2183.     }
  2184.     if (curwp->w_ntrows <= n) {
  2185.         eprintf("Impossible change");
  2186.         return (FALSE);
  2187.     }
  2188.     if (curwp->w_wndp == adjwp) {        /* Grow below.        */
  2189.         lp = adjwp->w_linep;
  2190.         for (i=0; i<n && lback(lp)!=adjwp->w_bufp->b_linep; ++i)
  2191.             lp = lback(lp);
  2192.         adjwp->w_linep  = lp;
  2193.         adjwp->w_toprow -= n;
  2194.     } else {                /* Grow above.        */
  2195.         lp = curwp->w_linep;
  2196.         for (i=0; i<n && lp!=curbp->b_linep; ++i)
  2197.             lp = lforw(lp);
  2198.         curwp->w_linep  = lp;
  2199.         curwp->w_toprow += n;
  2200.     }
  2201.     curwp->w_ntrows -= n;
  2202.     adjwp->w_ntrows += n;
  2203.     curwp->w_flag |= WFMODE|WFHARD;
  2204.     adjwp->w_flag |= WFMODE|WFHARD;
  2205.     return (TRUE);
  2206. }
  2207.  
  2208. /*
  2209.  * Pick a window for a pop-up.
  2210.  * Split the screen if there is only
  2211.  * one window. Pick the uppermost window that
  2212.  * isn't the current window. An LRU algorithm
  2213.  * might be better. Return a pointer, or
  2214.  * NULL on error.
  2215.  */
  2216. WINDOW    *
  2217. wpopup()
  2218. {
  2219.     register WINDOW    *wp;
  2220.  
  2221.     if (wheadp->w_wndp == NULL
  2222.     && splitwind(FALSE, 0, KRANDOM) == FALSE)
  2223.         return (NULL);
  2224.     wp = wheadp;                /* Find window to use    */
  2225.     while (wp!=NULL && wp==curwp)
  2226.         wp = wp->w_wndp;
  2227.     return (wp);
  2228. }
  2229. SHAR_EOF
  2230. if test 9891 -ne "`wc -c < 'window.c'`"
  2231. then
  2232.     echo shar: error transmitting "'window.c'" '(should have been 9891 characters)'
  2233. fi
  2234. fi
  2235. echo shar: extracting "'word.c'" '(6222 characters)'
  2236. if test -f 'word.c'
  2237. then
  2238.     echo shar: will not over-write existing file "'word.c'"
  2239. else
  2240. cat << \SHAR_EOF > 'word.c'
  2241. /*
  2242.  * Name:    MicroEMACS
  2243.  *        Word mode commands.
  2244.  * Version:    29
  2245.  * Last edit:    05-Feb-86
  2246.  * By:        rex::conroy
  2247.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  2248.  *
  2249.  * The routines in this file
  2250.  * implement commands that work word at
  2251.  * a time. There are all sorts of word mode
  2252.  * commands. If I do any sentence and/or paragraph
  2253.  * mode commands, they are likely to be put in
  2254.  * this file.
  2255.  */
  2256. #include    "def.h"
  2257.  
  2258. /*
  2259.  * Move the cursor backward by
  2260.  * "n" words. All of the details of motion
  2261.  * are performed by the "backchar" and "forwchar"
  2262.  * routines. Error if you try to move beyond
  2263.  * the buffers.
  2264.  */
  2265. backword(f, n, k)
  2266. {
  2267.     if (n < 0)
  2268.         return (forwword(f, -n, KRANDOM));
  2269.     if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2270.         return (FALSE);
  2271.     while (n--) {
  2272.         while (inword() == FALSE) {
  2273.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2274.                 return (FALSE);
  2275.         }
  2276.         while (inword() != FALSE) {
  2277.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2278.                 return (FALSE);
  2279.         }
  2280.     }
  2281.     return (forwchar(FALSE, 1, KRANDOM));
  2282. }
  2283.  
  2284. /*
  2285.  * Move the cursor forward by
  2286.  * the specified number of words. All of the
  2287.  * motion is done by "forwchar". Error if you
  2288.  * try and move beyond the buffer's end.
  2289.  */
  2290. forwword(f, n, k)
  2291. {
  2292.     if (n < 0)
  2293.         return (backword(f, -n, KRANDOM));
  2294.     while (n--) {
  2295.         while (inword() == FALSE) {
  2296.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2297.                 return (FALSE);
  2298.         }
  2299.         while (inword() != FALSE) {
  2300.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2301.                 return (FALSE);
  2302.         }
  2303.     }
  2304.     return (TRUE);
  2305. }
  2306.  
  2307. /*
  2308.  * Move the cursor forward by
  2309.  * the specified number of words. As you move,
  2310.  * convert any characters to upper case. Error
  2311.  * if you try and move beyond the end of the
  2312.  * buffer.
  2313.  */
  2314. upperword(f, n, k)
  2315. {
  2316.     register int    c;
  2317.  
  2318.     if (n < 0)
  2319.         return (FALSE);
  2320.     while (n--) {
  2321.         while (inword() == FALSE) {
  2322.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2323.                 return (FALSE);
  2324.         }
  2325.         while (inword() != FALSE) {
  2326.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  2327.             if (ISLOWER(c) != FALSE) {
  2328.                 c = TOUPPER(c);
  2329.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  2330.                 lchange(WFHARD);
  2331.             }
  2332.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2333.                 return (FALSE);
  2334.         }
  2335.     }
  2336.     return (TRUE);
  2337. }
  2338.  
  2339. /*
  2340.  * Move the cursor forward by
  2341.  * the specified number of words. As you move
  2342.  * convert characters to lower case. Error if you
  2343.  * try and move over the end of the buffer.
  2344.  */
  2345. lowerword(f, n, k)
  2346. {
  2347.     register int    c;
  2348.  
  2349.     if (n < 0)
  2350.         return (FALSE);
  2351.     while (n--) {
  2352.         while (inword() == FALSE) {
  2353.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2354.                 return (FALSE);
  2355.         }
  2356.         while (inword() != FALSE) {
  2357.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  2358.             if (ISUPPER(c) != FALSE) {
  2359.                 c = TOLOWER(c);
  2360.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  2361.                 lchange(WFHARD);
  2362.             }
  2363.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2364.                 return (FALSE);
  2365.         }
  2366.     }
  2367.     return (TRUE);
  2368. }
  2369.  
  2370. /*
  2371.  * Move the cursor forward by
  2372.  * the specified number of words. As you move
  2373.  * convert the first character of the word to upper
  2374.  * case, and subsequent characters to lower case. Error
  2375.  * if you try and move past the end of the buffer.
  2376.  */
  2377. capword(f, n, k)
  2378. {
  2379.     register int    c;
  2380.  
  2381.     if (n < 0)
  2382.         return (FALSE);
  2383.     while (n--) {
  2384.         while (inword() == FALSE) {
  2385.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2386.                 return (FALSE);
  2387.         }
  2388.         if (inword() != FALSE) {
  2389.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  2390.             if (ISLOWER(c) != FALSE) {
  2391.                 c = TOUPPER(c);
  2392.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  2393.                 lchange(WFHARD);
  2394.             }
  2395.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2396.                 return (FALSE);
  2397.             while (inword() != FALSE) {
  2398.                 c = lgetc(curwp->w_dotp, curwp->w_doto);
  2399.                 if (ISUPPER(c) != FALSE) {
  2400.                     c = TOLOWER(c);
  2401.                     lputc(curwp->w_dotp, curwp->w_doto, c);
  2402.                     lchange(WFHARD);
  2403.                 }
  2404.                 if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2405.                     return (FALSE);
  2406.             }
  2407.         }
  2408.     }
  2409.     return (TRUE);
  2410. }
  2411.  
  2412. /*
  2413.  * Kill forward by "n" words. The rules for final
  2414.  * status are now different. It is not considered an error
  2415.  * to delete fewer words than you asked. This lets you say
  2416.  * "kill lots of words" and have the command stop in a reasonable
  2417.  * way when it hits the end of the buffer. Normally this is
  2418.  */
  2419. delfword(f, n, k)
  2420. {
  2421.     register int    size;
  2422.     register LINE    *dotp;
  2423.     register int    doto;
  2424.  
  2425.     if (n < 0)
  2426.         return (FALSE);
  2427.     if ((lastflag&CFKILL) == 0)        /* Purge kill buffer.    */
  2428.         kdelete();
  2429.     thisflag |= CFKILL;
  2430.     dotp = curwp->w_dotp;
  2431.     doto = curwp->w_doto;
  2432.     size = 0;
  2433.     while (n--) {
  2434.         while (inword() == FALSE) {
  2435.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2436.                 goto out;    /* Hit end of buffer.    */
  2437.             ++size;
  2438.         }
  2439.         while (inword() != FALSE) {
  2440.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2441.                 goto out;    /* Hit end of buffer.    */
  2442.             ++size;
  2443.         }
  2444.     }
  2445. out:
  2446.     curwp->w_dotp = dotp;
  2447.     curwp->w_doto = doto;
  2448.     return (ldelete(size, TRUE));
  2449. }
  2450.  
  2451. /*
  2452.  * Kill backwards by "n" words. The rules
  2453.  * for success and failure are now different, to prevent
  2454.  * strange behavior at the start of the buffer. The command
  2455.  * only fails if something goes wrong with the actual delete
  2456.  * of the characters. It is successful even if no characters
  2457.  * are deleted, or if you say delete 5 words, and there are
  2458.  * only 4 words left. I considered making the first call
  2459.  * to "backchar" special, but decided that that would just
  2460.  * be wierd. Normally this is bound to "M-Rubout" and
  2461.  * to "M-Backspace".
  2462.  */
  2463. delbword(f, n, k)
  2464. {
  2465.     register int    size;
  2466.  
  2467.     if (n < 0)
  2468.         return (FALSE);
  2469.     if ((lastflag&CFKILL) == 0)        /* Purge kill buffer.    */
  2470.         kdelete();
  2471.     thisflag |= CFKILL;
  2472.     if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2473.         return (TRUE);            /* Hit buffer start.    */
  2474.     size = 1;                /* One deleted.        */
  2475.     while (n--) {
  2476.         while (inword() == FALSE) {
  2477.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2478.                 goto out;    /* Hit buffer start.    */
  2479.             ++size;
  2480.         }
  2481.         while (inword() != FALSE) {
  2482.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2483.                 goto out;    /* Hit buffer start.    */
  2484.             ++size;
  2485.         }
  2486.     }
  2487.     if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2488.         return (FALSE);
  2489.     --size;                    /* Undo assumed delete.    */
  2490. out:
  2491.     return (ldelete(size, TRUE));
  2492. }
  2493.  
  2494. /*
  2495.  * Return TRUE if the character at dot
  2496.  * is a character that is considered to be
  2497.  * part of a word. The word character list is hard
  2498.  * coded. Should be setable.
  2499.  */
  2500. inword()
  2501. {
  2502.     if (curwp->w_doto == llength(curwp->w_dotp))
  2503.         return (FALSE);
  2504.     if (ISWORD(lgetc(curwp->w_dotp, curwp->w_doto)) != FALSE)
  2505.         return (TRUE);
  2506.     return (FALSE);
  2507. }
  2508. SHAR_EOF
  2509. if test 6222 -ne "`wc -c < 'word.c'`"
  2510. then
  2511.     echo shar: error transmitting "'word.c'" '(should have been 6222 characters)'
  2512. fi
  2513. fi
  2514. exit 0
  2515. #    End of shell archive
  2516.